package io.gitee.bowen_lee.lbwio.group_boss_worker;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.Channel;
import java.nio.channels.ServerSocketChannel;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 创建线程(selector) 、bind() 、register()
 * 
 * @author Bowen
 * @since 2022-01-06 09:39:31
 */
public class SelectorThreadGroup {

  SelectorThread[] sts;
  ServerSocketChannel server = null;

  AtomicInteger xid;

  /**
   * 构造
   * 
   * @param num 线程数
   */
  public SelectorThreadGroup(int num) {
    sts = new SelectorThread[num];
    xid = new AtomicInteger(num);
    for (int i = 0; i < sts.length; i++) {
      sts[i] = new SelectorThread(this);
      new Thread(sts[i]).start();
    }
  }

  /**
   * 绑定
   * 
   * @param port 端口号
   */
  public void bind(int port) {
    try {
      server = ServerSocketChannel.open();
      // 设置 非阻塞
      server.configureBlocking(false);
      server.bind(new InetSocketAddress(port));

      // 注册
      serverRegister(server);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  /**
   * 注册 使用开关来设置 线程执行顺序<br/>
   * 此外还可以使用 wakeup() 来取消selector.select() 的阻塞
   * 
   * @param server2
   */
  public void serverRegister(Channel server) {
    // 获取一个 selector ，把channel 送过去并且开启一次select()的阻塞，就不管了
    SelectorThread st = next(server);
    System.out.println(st.curentThread.getId() + "注册执行前" + st.selector.keys().size());
    st.channel = server;
    System.out.println(st.curentThread.getId() + "注册执行后" + st.selector.keys().size());
    st.selector.wakeup();
    // if (server instanceof ServerSocketChannel) {
    // ServerSocketChannel ssc = (ServerSocketChannel) server;
    // try {
    // System.out.println(selectorThread.curentThread.getId() + "注册执行前" +
    // selectorThread.selector.keys().size());
    // ssc.register(selectorThread.selector, SelectionKey.OP_ACCEPT);
    // System.out.println(selectorThread.curentThread.getId() + "注册执行后" +
    // selectorThread.selector.keys().size());
    // selectorThread.ab.set(true);
    // } catch (ClosedChannelException e) {
    // e.printStackTrace();
    // }

  }

  /**
   * 获取将要注册的 SelectorThread 对象<br/>
   * 此处 将会区分 boss 和worker 角色 <br/>
   * boss 只做 accept() 处理，worker做R/W处理
   * 
   * @param c Channel
   * @return
   */
  private SelectorThread next(Channel c) {
    // 处理边界
    if (sts.length == 1) {
      return sts[0];
    }
    // 处理通用情况
    // 当是 ServerSocketChannel的时候，只能注册到boss角色的 selector 中。也就是下标是0的 selectorThread对象
    if (c instanceof ServerSocketChannel) {
      return sts[0];
    } else {
      // 取模的时候 去掉固定的boss 。
      return sts[xid.incrementAndGet() % (sts.length - 1) + 1];
    }
  }

}
